"""
人脸检测应用配置管理器
"""
import os
import yaml
import logging
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, Any, Optional, List

logger = logging.getLogger(__name__)


@dataclass 
class AppConfig:
    """应用基本配置"""
    name: str = "人脸检测应用"
    version: str = "1.0.0"
    environment: str = "development"


@dataclass
class ServerConfig:
    """服务器配置"""
    host: str = "0.0.0.0"
    port: int = 8003
    debug: bool = False


@dataclass
class LoggingConfig:
    """日志配置"""
    level: str = "INFO"
    format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"


@dataclass
class ModelConfig:
    """模型配置"""
    path: str = "models/yolo11n_face_detect_bayese_320x320_nv12.bin"
    confidence_threshold: float = 0.6
    iou_threshold: float = 0.45


@dataclass
class CameraConfig:
    """摄像头配置"""
    device_path: str = "/dev/video0"
    width: int = 640
    height: int = 480
    fps: int = 30
    async_capture: bool = True


@dataclass
class WebConfig:
    """Web界面配置"""
    video_quality: int = 80
    stream_fps: int = 15
    show_detection_boxes: bool = True
    show_center_point: bool = True
    show_stats: bool = True


@dataclass
class DetectionConfig:
    """检测配置"""
    class_names: List[str] = field(default_factory=lambda: ["face"])
    box_color: List[int] = field(default_factory=lambda: [0, 255, 0])  # BGR绿色
    text_color: List[int] = field(default_factory=lambda: [255, 255, 255])  # BGR白色
    line_thickness: int = 2
    font_scale: float = 0.6


@dataclass
class FaceDetectionAppConfig:
    """人脸检测应用总配置"""
    app: AppConfig = field(default_factory=AppConfig)
    server: ServerConfig = field(default_factory=ServerConfig)
    logging: LoggingConfig = field(default_factory=LoggingConfig)
    model: ModelConfig = field(default_factory=ModelConfig)
    camera: CameraConfig = field(default_factory=CameraConfig)
    web: WebConfig = field(default_factory=WebConfig)
    detection: DetectionConfig = field(default_factory=DetectionConfig)


class ConfigManager:
    """配置管理器"""
    
    def __init__(self, config_file: Optional[str] = None):
        self.config_file = config_file or "config/face_config.yaml"
        self.config: Optional[FaceDetectionAppConfig] = None
    
    def load_config(self) -> FaceDetectionAppConfig:
        """加载配置文件"""
        config_path = Path(self.config_file)
        
        if not config_path.exists():
            logger.warning(f"配置文件不存在: {config_path}，使用默认配置")
            self.config = FaceDetectionAppConfig()
            self._save_default_config(config_path)
            return self.config
        
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                config_data = yaml.safe_load(f)
            
            self.config = self._parse_config(config_data)
            self._load_env_variables()
            self._validate_config()
            
            logger.info(f"✅ 配置文件加载成功: {config_path}")
            return self.config
            
        except Exception as e:
            logger.error(f"❌ 加载配置文件失败: {e}，使用默认配置")
            self.config = FaceDetectionAppConfig()
            return self.config
    
    def _parse_config(self, config_data: Dict[str, Any]) -> FaceDetectionAppConfig:
        """解析配置数据"""
        config = FaceDetectionAppConfig()
        
        # 解析应用配置
        if 'app' in config_data:
            app_data = config_data['app']
            config.app = AppConfig(
                name=app_data.get('name', config.app.name),
                version=app_data.get('version', config.app.version),
                environment=app_data.get('environment', config.app.environment)
            )
        
        # 解析服务器配置
        if 'server' in config_data:
            server_data = config_data['server']
            config.server = ServerConfig(
                host=server_data.get('host', config.server.host),
                port=server_data.get('port', config.server.port),
                debug=server_data.get('debug', config.server.debug)
            )
        
        # 解析日志配置
        if 'logging' in config_data:
            logging_data = config_data['logging']
            config.logging = LoggingConfig(
                level=logging_data.get('level', config.logging.level),
                format=logging_data.get('format', config.logging.format)
            )
        
        # 解析模型配置
        if 'model' in config_data:
            model_data = config_data['model']
            config.model = ModelConfig(
                path=model_data.get('path', config.model.path),
                confidence_threshold=model_data.get('confidence_threshold', config.model.confidence_threshold),
                iou_threshold=model_data.get('iou_threshold', config.model.iou_threshold)
            )
        
        # 解析摄像头配置
        if 'camera' in config_data:
            camera_data = config_data['camera']
            config.camera = CameraConfig(
                device_path=camera_data.get('device_path', config.camera.device_path),
                width=camera_data.get('width', config.camera.width),
                height=camera_data.get('height', config.camera.height),
                fps=camera_data.get('fps', config.camera.fps),
                async_capture=camera_data.get('async_capture', config.camera.async_capture)
            )
        
        # 解析Web配置
        if 'web' in config_data:
            web_data = config_data['web']
            config.web = WebConfig(
                video_quality=web_data.get('video_quality', config.web.video_quality),
                stream_fps=web_data.get('stream_fps', config.web.stream_fps),
                show_detection_boxes=web_data.get('show_detection_boxes', config.web.show_detection_boxes),
                show_center_point=web_data.get('show_center_point', config.web.show_center_point),
                show_stats=web_data.get('show_stats', config.web.show_stats)
            )
        
        # 解析检测配置
        if 'detection' in config_data:
            detection_data = config_data['detection']
            config.detection = DetectionConfig(
                class_names=detection_data.get('class_names', config.detection.class_names),
                box_color=detection_data.get('box_color', config.detection.box_color),
                text_color=detection_data.get('text_color', config.detection.text_color),
                line_thickness=detection_data.get('line_thickness', config.detection.line_thickness),
                font_scale=detection_data.get('font_scale', config.detection.font_scale)
            )
        
        return config
    
    def _load_env_variables(self):
        """从环境变量加载配置覆盖"""
        if self.config:
            # 服务器配置覆盖
            host = os.getenv("FACE_SERVER_HOST")
            if host:
                self.config.server.host = host
                logger.info(f"服务器主机地址已从环境变量覆盖: {host}")
            
            port = os.getenv("FACE_SERVER_PORT")
            if port:
                try:
                    self.config.server.port = int(port)
                    logger.info(f"服务器端口已从环境变量覆盖: {port}")
                except ValueError:
                    logger.warning(f"无效的服务器端口环境变量: {port}")
            
            debug = os.getenv("FACE_SERVER_DEBUG")
            if debug:
                self.config.server.debug = debug.lower() in ('true', '1', 'yes', 'on')
                logger.info(f"调试模式已从环境变量覆盖: {self.config.server.debug}")
            
            # 模型配置覆盖
            model_path = os.getenv("FACE_MODEL_PATH")
            if model_path:
                self.config.model.path = model_path
                logger.info(f"模型路径已从环境变量覆盖: {model_path}")
            
            # 摄像头配置覆盖
            camera_device = os.getenv("FACE_CAMERA_DEVICE")
            if camera_device:
                self.config.camera.device_path = camera_device
                logger.info(f"摄像头设备路径已从环境变量覆盖: {camera_device}")
            
            # 日志级别覆盖
            log_level = os.getenv("FACE_LOG_LEVEL")
            if log_level:
                self.config.logging.level = log_level.upper()
                logger.info(f"日志级别已从环境变量覆盖: {log_level}")
    
    def _validate_config(self):
        """验证配置参数"""
        if not self.config:
            return
        
        # 验证服务器端口
        if not (1 <= self.config.server.port <= 65535):
            raise ValueError(f"无效的端口号: {self.config.server.port}")
        
        # 验证模型文件路径
        model_path = Path(self.config.model.path)
        if not model_path.is_absolute():
            # 相对路径，相对于项目根目录
            project_root = Path(__file__).parent.parent
            full_model_path = project_root / model_path
            if not full_model_path.exists():
                logger.warning(f"模型文件不存在: {full_model_path}")
        
        # 验证阈值范围
        if not (0.0 <= self.config.model.confidence_threshold <= 1.0):
            raise ValueError(f"无效的置信度阈值: {self.config.model.confidence_threshold}")
        
        if not (0.0 <= self.config.model.iou_threshold <= 1.0):
            raise ValueError(f"无效的IOU阈值: {self.config.model.iou_threshold}")
        
        # 验证摄像头配置
        if not self.config.camera.device_path:
            logger.warning("摄像头设备路径未设置，将使用默认路径 /dev/video0")
            self.config.camera.device_path = "/dev/video0"
        
        logger.info("✅ 配置验证通过")
    
    def _save_default_config(self, config_path: Path):
        """保存默认配置文件"""
        try:
            config_path.parent.mkdir(parents=True, exist_ok=True)
            
            default_config = {
                'app': {
                    'name': '人脸检测应用',
                    'version': '1.0.0',
                    'environment': 'development'
                },
                'server': {
                    'host': '0.0.0.0',
                    'port': 8003,
                    'debug': False
                },
                'logging': {
                    'level': 'INFO',
                    'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
                },
                'model': {
                    'path': 'models/yolo11n_face_detect_bayese_320x320_nv12.bin',
                    'confidence_threshold': 0.6,
                    'iou_threshold': 0.45  # 固定IOU阈值，不对外暴露调节
                },
                'camera': {
                    'device_path': '/dev/video0',
                    'width': 640,
                    'height': 480,
                    'fps': 30,
                    'async_capture': True
                },
                'web': {
                    'video_quality': 80,
                    'stream_fps': 15,
                    'show_detection_boxes': True,
                    'show_center_point': True,
                    'show_stats': True
                },
                'detection': {
                    'class_names': ['face'],
                    'box_color': [0, 255, 0],
                    'text_color': [255, 255, 255],
                    'line_thickness': 2,
                    'font_scale': 0.6
                }
            }
            
            with open(config_path, 'w', encoding='utf-8') as f:
                yaml.dump(default_config, f, default_flow_style=False, allow_unicode=True)
            
            logger.info(f"默认配置文件已保存: {config_path}")
            
        except Exception as e:
            logger.error(f"保存默认配置文件失败: {e}")
    
    def get_config(self) -> FaceDetectionAppConfig:
        """获取配置"""
        if self.config is None:
            self.load_config()
        return self.config
    
    def get_model_path(self) -> Path:
        """获取模型文件的绝对路径"""
        if not self.config:
            self.load_config()
        
        model_path = Path(self.config.model.path)
        if not model_path.is_absolute():
            # 相对路径，相对于项目根目录
            project_root = Path(__file__).parent.parent
            model_path = project_root / model_path
        
        return model_path


# 全局配置管理器实例
config_manager = ConfigManager()


def get_config() -> FaceDetectionAppConfig:
    """获取应用配置"""
    return config_manager.get_config()


def get_model_path() -> Path:
    """获取模型文件路径"""
    return config_manager.get_model_path()